package com.ygqh.common.okhttp;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.ygqh.common.okhttp.exception.OkHttp3Exception;
import com.ygqh.common.utils.IOUtil;
import com.ygqh.localsign.response.AbstractResponse;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 〈〉
 *
 * @author guohao
 * @date 2019/3/18 15:54
 * @since 1.0.0
 */
@Slf4j
public class DefaultOkHttp3Client {
    public static final MediaType FORM_MEDIA_TYPE = MediaType.parse("application/x-www-form-urlencoded");
    public static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json");
    public static final int TIME_OUT = 30;
    private final static OkHttpClient OK_HTTP_CLIENT;
    protected final static Charset CHARSET = Charset.forName("UTF-8");

    static {
        //创建我们Client对象的构建者
        OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
        okHttpBuilder
                //为构建者填充超时时间
                .connectTimeout(TIME_OUT, TimeUnit.SECONDS)
                .readTimeout(TIME_OUT, TimeUnit.SECONDS)
                .writeTimeout(TIME_OUT, TimeUnit.SECONDS)
                //允许重定向
                .followRedirects(true)
                //添加https支持
                .hostnameVerifier((s, sslSession) -> true)
                .sslSocketFactory(HttpsUtils.initSSLSocketFactory(), HttpsUtils.initTrustManager());
        OK_HTTP_CLIENT = okHttpBuilder.build();
    }

    /**
     * Get方法调用服务
     */
    public static Response httpGet(HttpUrl url) throws OkHttp3Exception {
        Request request = new Request.Builder()
                .url(url)
                .build();
        return doExecute(request);
    }

    /**
     * Post方法调用服务
     */
    public static Response httpPost(String url, String content, MediaType mediaType) throws OkHttp3Exception {
        log.info("httpPost request -> url :{}, content : {}, mediaType : {}", url, content, mediaType);
        RequestBody requestBody = RequestBody.create(mediaType, content);
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        return doExecute(request);
    }

    public static Response httpFormPost(String url, Map<String, String> params) throws OkHttp3Exception {
        log.info("httpPost request -> url :{}, params : {}", url, params);
        FormBody.Builder builder = new FormBody.Builder();
        params.forEach(builder::add);
        RequestBody requestBody = builder.build();
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        return doExecute(request);
    }


    private static Response doExecute(Request request) throws OkHttp3Exception {
        try {
            return OK_HTTP_CLIENT.newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
            throw new OkHttp3Exception("IO error on " + e.getMessage());
        }
    }


    public static <T extends AbstractResponse> T httpFormPost(String url, Map<String, String> params, TypeReference<T> typeReference) throws OkHttp3Exception {
        Response response = httpFormPost(url, params);
        return getAsObject(response, typeReference);
    }

    public static <T extends AbstractResponse> T httpPost(String url, String content, MediaType mediaType, TypeReference<T> typeReference) throws OkHttp3Exception {
        Response response = httpPost(url, content, mediaType);
        return getAsObject(response, typeReference);
    }

    private static <T extends AbstractResponse> T getAsObject(Response response, TypeReference<T> typeReference) throws OkHttp3Exception {
        Class<T> clazz = (Class<T>) typeReference.getType();
        try {
            byte[] bytes = IOUtil.toByteArray(response.body().byteStream());
            System.out.println(new String(bytes));
            System.out.println(new String(bytes));
            return JSON.parseObject(bytes, 0, bytes.length, CHARSET.newDecoder(),
                    clazz);
        } catch (IOException e) {
            e.printStackTrace();
            throw new OkHttp3Exception("IO error on convert to " + clazz, e);
        }

    }


}
